/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.util;

import java.io.ByteArrayInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/** This is a utility class which performs several DOM to SOAPElement related 
    functions. 

    @author Shrideep Pallickara
    $Date: 2005/07/29 22:41:29 $
    $Revision: 1.3 $
*/

public class SoapDOMConversion {

  private static DocumentBuilderFactory documentBuilderFactory = null;
  
  private static DocumentBuilder documentBuilder = null;
  
  public final static String SOAP_ENVELOPE_NAMESPACE_URI = 
  "http://schemas.xmlsoap.org/soap/envelope/";

  private static SOAPFactory soapFactory;

  private static SoapDOMConversion instance = new SoapDOMConversion();
  
  

  private SoapDOMConversion() {
    try {
      documentBuilderFactory = DocumentBuilderFactory.newInstance();
      documentBuilderFactory.setNamespaceAware(true);
      documentBuilder = documentBuilderFactory.newDocumentBuilder();
      soapFactory = SOAPFactory.newInstance();
    } catch (Exception e) {
      System.out.println(e);
    }
  }

  public static SoapDOMConversion getInstance() {
    return instance;
  }


  /** This method converts a SOAPMessage into a org.w3c.dom.Document object. */
  public Document 
  convertToDOMDocument(SOAPMessage soapMessage) throws Exception {
    if (soapMessage == null) { 
      return null; 
    }

    String xmlStr = SoapPrinter.getStringRepresentation(soapMessage);
    ByteArrayInputStream input = 
      new ByteArrayInputStream(xmlStr.getBytes());
    Document doc = documentBuilder.parse(input);
    return doc;
  }

  /** This method extracts the SOAPHeader from a document. The element returned
      is of the type org.w3c.dom.Element. This method currently works with the
      soapEnvelope namespace corresponding to SOAP1.1 and the one that is 
      currently approved by WSI. This method throws an error if there are more
      than 1 SOAP  header elements in the SOAPMessage*/  
  public Element extractSOAPHeader(Document document) throws Exception {
    Element soapHeader = null;
    NodeList nodeList = 
      document.getElementsByTagNameNS(SOAP_ENVELOPE_NAMESPACE_URI, "Header");
    
    /** There can be only 1 header within a SOAPMessage. */ 
    if ( nodeList.getLength() > 1 ) {
      System.out.println("This is an error ");
      return null;
    }

    /** It is possible that the SOAPMessage has no headers */
    if ( nodeList.getLength() == 0 ) { 
      return null;
    }
    soapHeader = (Element) nodeList.item(0);
    return soapHeader;
  }



  /** This method extracts the SOAPBody from a document. The element returned 
      is of the type org.w3c.dom.Element. This method currently works with the
      soapEnvelope namespace corresponding to SOAP1.1 and the one that is 
      currently approved by WSI. This method throws an error if there isn't 
      EXACTLY ONE   SOAPBody element in the SOAPMessage*/  
  public Element extractSOAPBody(Document document) throws Exception {
     Element soapBody = null;
     NodeList nodeList =
       document.getElementsByTagNameNS
       (SOAP_ENVELOPE_NAMESPACE_URI, "Body");
     if ( nodeList.getLength() != 1 ) {
       System.out.println("This is an error ");
       return null;
     }
     
     soapBody = (Element) nodeList.item(0);
     return soapBody;
  }



  /** Checks to see if the <i>element</i> in question contains an element
      referred to the specified <i>localName</i> and <i>prefixUri</i>*/
  public boolean hasElement(Element element, String localName, 
			    String prefixUri) {
    NodeList nodeList = element.getElementsByTagNameNS(prefixUri, localName);
    if (nodeList != null) {
      return true;
    }
    
    return false;
  }



  /** This method retrieves a child element based on both the localName and 
      prefixUri associated with the element in the question. This method throws
      an exception if any of the argument passed to this method are null */  
  public Element 
  getElement(Element element, String localName, String prefixUri) { 
    
    NodeList nodeList = element.getElementsByTagNameNS(prefixUri, localName);
    if (nodeList != null) {
      Element returnElement = (Element) nodeList.item(0);
      if (returnElement == null) {
	System.out.println("Return element is NULL!! for "  + localName + 
			   " uri:" + prefixUri);
      }
      return returnElement;
    }

    System.out.println("Returning null! for " + localName + " uri:" +
		       prefixUri);
    return null;
  }


  /** This method retrieves a child element based on just the localName 
      associated with the element in question.*/  
  public Element 
  getElement(Element element, String localName) {
 
    NodeList nodeList = element.getElementsByTagName(localName);
    if (nodeList != null) {
      Element returnElement = (Element) nodeList.item(0);
      if (returnElement == null) {
	System.out.println("Return element is NULL!! for "  + localName);
      }
      return returnElement;
    }
    System.out.println("Returning null! for " + localName);
    return null;
  }
  


  /** This method converts a w3c DOM Node into a javax.xml.SOAPElement. This
      method is needed since it is not possible to simply cast these objects 
      into one another since they are part of the inheritance tree. This 
      method converts the DOM node into the corresponding SOAPElement. If this
      node has child nodes these are converted into the appropriate 
      SOAPElements and add as child elements to the root SOAPElement. */
  public SOAPElement
  convertDOMNodeToSOAPElement(Node node, SOAPEnvelope soapEnvelope) 
    throws Exception {
   
    String localName = node.getLocalName();
    String prefix = node.getPrefix();
    String uri = node.getNamespaceURI();

    SOAPElement soapElement = 
      soapFactory.createElement(localName, prefix, uri);
    
    if (node.hasChildNodes()) {
      addChildNodes(node, soapElement, soapEnvelope); 
    }

    return soapElement;
  }


  /** This method adds child nodes of the specified w3c DOM Node to the 
      specified javax.soap.SOAPElement. This method cycles through the DOM 
      child nodes and converts the DOM child nodes into the corresponding 
      SOAPElements, which are then added as child elements to the root 
      SOAPElement. */
  public SOAPElement 
  addChildNodes(Node node, SOAPElement soapElement, SOAPEnvelope soapEnvelope) 
    throws Exception {
    
    if (node.hasChildNodes()) {
      NodeList nodeList = node.getChildNodes();

      for (int i=0; i < nodeList.getLength(); i++) {
	org.w3c.dom.Node childNode = (org.w3c.dom.Node) nodeList.item(i);
	addChildNode(childNode, soapElement, soapEnvelope);
      }
      
    }
    
    return soapElement;
  }
  

  /** This method adds a w3c DOM node to the specified javax.soap.SOAPElement.
      This method also deals with the case where there are mutliple child 
      nodes within  the specified node in question */
  public SOAPElement 
  addChildNode(Node node, SOAPElement soapElement, SOAPEnvelope soapEnvelope)
    throws Exception {
    String localName = node.getLocalName();
    String prefix = node.getPrefix();
    String uri = node.getNamespaceURI();
    
    System.out.println("Adding child node " + node );
    if (node.getNodeType() == node.TEXT_NODE && node.getNodeValue() != null ) {
      String val = node.getNodeValue().trim();
      if (val != "") { 
	System.out.println("Adding text node ");
	soapElement.addTextNode(node.getNodeValue());
      }
      return soapElement;
    }

    SOAPElement soapChildElement = 
      soapFactory.createElement(localName, prefix, uri);
    
    if (node.hasChildNodes()) {
      addChildNodes(node, soapChildElement, soapEnvelope);
    }
    
    soapElement.addChildElement(soapChildElement);
    return soapElement;
  }

}





